/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { DfuDeviceSelector } from '../../DfuDeviceSelector'
import { WorkerMsg, WorkCmd } from '../../WorkMsg'
import hilog from '@ohos.hilog';
import ble from '@ohos.bluetooth.ble';
import { JSON } from '@kit.ArkTS';
import json from '@ohos.util.json';

export class BootloaderScanner {
  private TAG: string = 'BootloaderScanner';
  private DOMAIN: number = 0x8632;

  private mDeviceAddress: string;
  private mDeviceAddressIncremented: string;
  private mDfuServiceUuid: string;
  private mSelector: DfuDeviceSelector;
  private mBootloaderAddress: string;
  private mFound: boolean = false;
  private mWmsg: WorkerMsg;

  constructor(deviceAddress: string, deviceAddressIncremented: string, dfuServiceUuid: string, wmsg: WorkerMsg) {
    this.mDeviceAddress = deviceAddress;
    this.mDeviceAddressIncremented = deviceAddressIncremented;
    this.mDfuServiceUuid = dfuServiceUuid;
    this.mWmsg = wmsg;
  }

  public onReceiveEvent(data: Array<ble.ScanResult>) {
    // hilog.info(this.DOMAIN, this.TAG, 'BLE scan device find result = '+ JSON.stringify(data));
    for (const sres of data) {
      if (!this.mFound && this.mSelector.matches(sres, sres.rssi, null, this.mDeviceAddress,
          this.mDeviceAddressIncremented, this.mWmsg.deviceName)) {
        hilog.info(this.DOMAIN, this.TAG, `Found Device: ${JSON.stringify(sres)}`);
        this.mBootloaderAddress = sres.deviceId;
        this.mFound = true;

        this.mWmsg.deviceAddress = sres.deviceId;
        this.mWmsg.cmd = WorkCmd.WC_RESTART_SERVICE;
        try {
          let wmsg: WorkerMsg = {
            cmd: WorkCmd.WC_RESTART_SERVICE,
            deviceAddress: sres.deviceId,
            deviceName: this.mWmsg.deviceName,
            disableNotification: this.mWmsg.disableNotification,
            startAsForegroundService: this.mWmsg.startAsForegroundService,
            mimeType: this.mWmsg.mimeType,
            fileType: this.mWmsg.fileType,
            fileUri: this.mWmsg.fileUri,
            filePath: this.mWmsg.filePath,
            fileResId: this.mWmsg.fileResId,
            initFileUri: this.mWmsg.initFileUri,
            initFilePath: this.mWmsg.initFilePath,
            initFileResId: this.mWmsg.initFileResId,
            keepBond: this.mWmsg.keepBond,
            restoreBond: this.mWmsg.restoreBond,
            forceDfu: this.mWmsg.forceDfu,
            forceScanningForNewAddressInLegacyDfu: this.mWmsg.forceScanningForNewAddressInLegacyDfu,
            disableResume: this.mWmsg.disableResume,
            numberOfRetries: this.mWmsg.numberOfRetries,
            mbrSize: this.mWmsg.mbrSize,
            dataObjectDelay: this.mWmsg.dataObjectDelay,
            scanTimeout: this.mWmsg.scanTimeout,
            rebootTime: this.mWmsg.rebootTime,
            mtu: this.mWmsg.mtu,
            currentMtu: this.mWmsg.currentMtu,
            enableUnsafeExperimentalButtonlessDfu: this.mWmsg.enableUnsafeExperimentalButtonlessDfu,
            packetReceiptNotificationsEnabled: this.mWmsg.packetReceiptNotificationsEnabled,
            numberOfPackets: this.mWmsg.numberOfPackets,
            legacyDfuUuids: this.mWmsg.legacyDfuUuids,
            secureDfuUuids: this.mWmsg.secureDfuUuids,
            experimentalButtonlessDfuUuids: this.mWmsg.experimentalButtonlessDfuUuids,
            buttonlessDfuWithoutBondSharingUuids: this.mWmsg.buttonlessDfuWithoutBondSharingUuids,
            buttonlessDfuWithBondSharingUuids: this.mWmsg.buttonlessDfuWithBondSharingUuids,
          }
          let pmsg: string = JSON.stringify(wmsg);
          this.mWmsg.workerPort?.postMessage(pmsg);
        } catch (e) {
          hilog.error(this.DOMAIN, this.TAG, `postMessage err: ${JSON.stringify(e)}`);
        }

        return;
        //TODO：just debug
        // let gattClient = ble.createGattClientDevice(sres.deviceId);
        // gattClient.on("BLEConnectionStateChange", async (stat: ble.BLEConnectionChangeState) => {
        //   hilog.info(this.DOMAIN, this.TAG, `ConnectState: ${JSON.stringify(stat)}`);
        //   let serviceList = await gattClient.getServices();
        //   hilog.info(this.DOMAIN, this.TAG, `GetServices: ${JSON.stringify(serviceList)}`);
        // })
        // gattClient.connect();
      }
    }
  }
  /**
   * Searches for the advertising bootloader. The bootloader may advertise with the same device
   * address or one with the last byte incremented by 1.
   * This method is a blocking one and ends when such device is found. There are two
   * implementations of this interface - one for Androids 4.3 and 4.4.x and one for the
   * Android 5+ devices.
   *
   * @param selector the device selector
   * @param timeout the scanning timeout, in milliseconds
   * @return the address of the advertising DFU bootloader. It may be the same as the application
   * address or one with the last byte incremented by 1 (AA:BB:CC:DD:EE:45/FF -&gt; AA:BB:CC:DD:EE:46/00).
   * Null is returned when Bluetooth is off or the device has not been found.
   */
  public searchUsing(selector: DfuDeviceSelector, timeout: number): string {
    let filters: Array<ble.ScanFilter> = selector.getScanFilters(this.mDfuServiceUuid);
    let scanFilter: ble.ScanFilter = {
      name:'MD2-HA20-F220231200085',
      // serviceUuid: 'FE59'
    };
    let scanOptions: ble.ScanOptions = {
      interval: 500,
      dutyMode: ble.ScanDuty.SCAN_MODE_LOW_POWER,
      matchMode: ble.MatchMode.MATCH_MODE_AGGRESSIVE,
    }
    hilog.info(this.DOMAIN, this.TAG, `searchUsing: ${JSON.stringify(filters)}, ${JSON.stringify(scanOptions)}`);
    ble.on("BLEDeviceFind", (data: Array<ble.ScanResult>) => {
      // hilog.info(this.DOMAIN, this.TAG, 'BLE scan device find result = '+ JSON.stringify(data));
      this.onReceiveEvent(data);
      if (this.mFound) {
        ble.stopBLEScan();
        ble.off('BLEDeviceFind');
      }
    });
    this.mFound = false;
    this.mSelector = selector;
    ble.startBLEScan(filters, scanOptions);
    // ble.startBLEScan([scanFilter], scanOptions);
    return null;
  };
}